home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / BlobMgr / Demo Folder / Pyramid.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  7.2 KB  |  315 lines  |  [TEXT/KAHL]

  1. /*
  2.  * Blob Manager Demonstration:  Pyramid module
  3.  * 
  4.  * This is played on a checkerboard.  Each player has 10 pieces
  5.  * arranged in a pyramid.  Moves are into adjacent diagonal squares,
  6.  * in either direction.  Jumps are also allowed, over either side's
  7.  * pieces.  The first player to reassemble a pyramid on the side
  8.  * opposite to that which he started on wins.
  9.  *
  10.  * I haven't thought about deadlock detection yet.  Probably never will.
  11.  *
  12.  * 11 August 1986        Paul DuBois
  13.  *
  14.  * 24 Dec 93
  15.  * - First two arguments to DrawBoardPos() were reversed.
  16.  * - Changed DrawBoardPos() to use RGB gray for dimmed positions when
  17.  * possible.
  18.  */
  19.  
  20. # include    "TransSkel.h"
  21.  
  22.  
  23. # include    "BlobMgr.h"
  24. # include    "BlobDemo.h"
  25.  
  26.  
  27. # define    rows        8        /* number of rows on board */
  28. # define    columns        8        /* number of columns on board */
  29. # define    pieceSize    20        /* size of each piece */
  30. # define    vMessage    165        /* vertical position of message */
  31.  
  32. # define    BoardPos(b,ph,pv)    FindCheckerBoardPos(b,&board,ph,pv)
  33. # define    PosEmpty(h,v)        CheckerBoardPosEmpty(&board,h,v)
  34. # define    PosFilled(h,v)        CheckerBoardPosFilled(&board,h,v)
  35.  
  36. static WindowPtr        wind;
  37.  
  38.  
  39. static BlobSetHandle    boardBlobs = nil;
  40. static CheckerBoard        board;
  41. static BlobSetHandle    donors = nil;
  42. static BlobHandle        current;
  43. static BlobHandle        pBlack;
  44. static BlobHandle        pWhite;
  45. static BlobHandle        lastXferPiece;
  46. static Boolean            lastWasJump;
  47. static BlobSetHandle    misc;
  48. static BlobHandle        resetBlob;    /* simulated control */
  49.  
  50. static short            hMid;
  51. static Boolean            paused;
  52. static Str255            statusStr = "\p";
  53.  
  54. /*
  55.  * Initial configuration
  56.  */
  57.  
  58. static short    layout[rows][columns] =    /* 0 = black, 1 = white, 2 = none */
  59. {
  60.     0,    2,    2,    2,    2,    2,    2,    2,
  61.     2,    0,    2,    2,    2,    2,    2,    1,
  62.     0,    2,    0,    2,    2,    2,    1,    2,
  63.     2,    0,    2,    0,    2,    1,    2,    1,
  64.     0,    2,    0,    2,    1,    2,    1,    2,
  65.     2,    0,    2,    2,    2,    1,    2,    1,
  66.     0,    2,    2,    2,    2,    2,    1,    2,
  67.     2,    2,    2,    2,    2,    2,    2,    1
  68. };
  69.  
  70.  
  71. static void
  72. StatusMesg (StringPtr s)
  73. {
  74. Rect    r;
  75.  
  76.     SetRect (&r, 0, vMessage, wind->portRect.right - 25, vMessage + 12);
  77.     TextBox    (s+1, (long) s[0], &r, teJustCenter);
  78.     StrCpy (statusStr, s);
  79. }
  80.  
  81.  
  82. /*
  83.  * Set the board to the initial configuration
  84.  */
  85.  
  86. static void
  87. Reset (void)
  88. {
  89. short        i, j, val;
  90. BlobHandle    b;
  91.  
  92.     UnglueGlobSet (boardBlobs);        /* clear all globs */
  93.     for (i = 0; i < columns; ++i)
  94.     {
  95.         for (j = 0; j < rows; ++j)
  96.         {
  97.             val = layout[i][j];
  98.             b = board[i][j];
  99.             DisposeBlobMatchSet (b);
  100.             if (val != 2)
  101.             {
  102.                 GlueGlob (GetBlobHandle (donors, val), b);
  103.                 NewBlobMatch (GetBlobHandle (donors, 1 - val), b);
  104.             }
  105.         }
  106.     }
  107.     current = pWhite;
  108.     StatusMesg ("\p");
  109.     paused = false;
  110.     lastWasJump = false;    /* last move wasn't a jump */
  111. }
  112.  
  113.  
  114. static void
  115. Pause (StringPtr msg)
  116. {
  117.     StatusMesg (msg);
  118.     paused = true;
  119. }
  120.  
  121.  
  122. /*
  123.  * Test whether a piece can move or not.  It can move if there's an
  124.  * empty adjacent diagonal, or a piece adjacent with an empty square
  125.  * on the other side of it.  If the last move was a jump, and the
  126.  * piece is the same one that jumped, then can only move if can
  127.  * keep jumping.
  128.  */
  129.  
  130. static Boolean
  131. CanMove (short h, short v)
  132. {
  133.     if (   (PosFilled (h - 1, v - 1) && PosEmpty (h - 2, v - 2))
  134.         || (PosFilled (h + 1, v - 1) && PosEmpty (h + 2, v - 2))
  135.         || (PosFilled (h - 1, v + 1) && PosEmpty (h - 2, v + 2))
  136.         || (PosFilled (h + 1, v + 1) && PosEmpty (h + 2, v + 2)))
  137.         return (true);
  138.  
  139.     if (board[h][v] == lastXferPiece && lastWasJump)
  140.         return (false);
  141.  
  142.     return (   PosEmpty (h - 1, v - 1)
  143.             || PosEmpty (h + 1, v - 1)
  144.             || PosEmpty (h - 1, v + 1)
  145.             || PosEmpty (h + 1, v + 1) );
  146. }
  147.  
  148.  
  149. /*
  150.  * Test for a win.  Pass the upper and lower limits on the rows to
  151.  * test (either the top or botton half of the board).
  152.  */
  153.  
  154. static Boolean
  155. TestWin (short loRow)
  156. {
  157. short        i, j;
  158. MatchHandle    m;
  159.  
  160.     for (i = loRow; i < loRow + rows / 2; ++i)
  161.     {
  162.         for (j = 0; j < columns; ++j)
  163.         {
  164.             if ((m = (**board[j][i]).matches) != nil
  165.                 && BGlob (board[j][i]) != (**m).mBlob)
  166.                 return (false);            /* at least one mismatch */
  167.         }
  168.     }
  169.     return (true);
  170. }
  171.  
  172.  
  173. /*
  174.  * When a piece is clicked on, the advisory checks whether the piece has
  175.  * any legal moves available to it.  If so, it returns true, so that
  176.  * BlobClick is allowed to drag the piece.  After the piece has been
  177.  * dragged, the advisory checks whether the position it was dragged to
  178.  * is legal, and returns true if so.
  179.  *
  180.  * Messages passed to the advisory follow the pattern
  181.  *
  182.  * { { advRClick advRClick* } advXfer* }*
  183.  *
  184.  * where * means 0 or more instances of the thing *'ed.  In particular,
  185.  * the advXfer message is never seen without a preceding advRClick.
  186.  */
  187.  
  188. static pascal Boolean
  189. Advisory (short mesg, BlobHandle b)
  190. {
  191. static short    h, v;    /* static to save board position of click on piece */
  192. short        h2, v2;
  193. Boolean        result;
  194.  
  195.     switch (mesg)
  196.     {
  197.  
  198.     case advRClick:    /* first click on piece */
  199.         if (BGlob (b) != current && !(b == lastXferPiece && lastWasJump))
  200.             return (false);
  201.         BoardPos (b, &h, &v);    /* find where it is */
  202.         return (CanMove (h, v));
  203.  
  204.     case advXfer:    /* Mouse released after dragging piece */
  205.  
  206.         BoardPos (b, &h2, &v2);
  207.         result =   (h2 == h - 1 || h2 == h + 1)
  208.                 && (v2 == v - 1 || v2 == v + 1);
  209.         if (result == true)
  210.             lastWasJump = false;
  211.         else
  212.         {
  213.             result =   (h2 == h - 2 || h2 == h + 2)
  214.                     && (v2 == v - 2 || v2 == v + 2)
  215.                     && PosFilled ((h + h2) / 2, (v + v2) / 2);
  216.             if (result == true)
  217.                 lastWasJump = true;
  218.         }
  219.         if (result == true)
  220.             lastXferPiece = b;
  221.         return (result);
  222.     }
  223. }
  224.  
  225.  
  226. static pascal void
  227. Mouse (Point pt, long t, short mods)
  228. {
  229.     if (TestBlob (resetBlob, pt))
  230.     {
  231.         if (BTrackMouse (resetBlob, pt, inFullBlob))
  232.             Reset ();
  233.     }
  234.     else if (!paused)
  235.     {
  236.         BlobClick (pt, t, nil, boardBlobs);
  237.         if (BClickResult () == bcXfer)
  238.         {
  239.             if (TestWin (0))
  240.                 Pause ("\pWhite Wins");
  241.             else if (TestWin (rows / 2))
  242.                 Pause ("\pBlack Wins");
  243.             else if (BGlob (lastXferPiece) == current)    /* switch if didn't move prev player */
  244.                 current = (current == pBlack ? pWhite : pBlack);
  245.         }
  246.     }
  247. }
  248.  
  249.  
  250. static pascal void
  251. Update (Boolean resized)
  252. {
  253.     DrawBlobSet (boardBlobs);
  254.     DrawBlobSet (misc);
  255.     StatusMesg (statusStr);
  256. }
  257.  
  258.  
  259. /*
  260.  * Activate the window:  Set the advisory function and set the permissions
  261.  * to transfer-only.  Clear, replace, duplication and swap are off.
  262.  * Since replace is off, the advisory doesn't have to check whether
  263.  * the dragged piece was dragged onto a blob that already has a glob.
  264.  *
  265.  * Deactivate the window:  Clear the advisory.
  266.  */
  267.  
  268. static pascal void
  269. Activate (Boolean active)
  270. {
  271.     if (active)
  272.     {
  273.         SetDragRects (wind);
  274.         SetBCPermissions (false, true, false, false, false);    /* xfer only */
  275.         SetBCAdvisory (Advisory);
  276.     }
  277.     else
  278.     {
  279.         SetBCAdvisory (nil);
  280.     }
  281. }
  282.  
  283.  
  284. void
  285. PyrInit (void)
  286. {
  287. Rect    r;
  288.  
  289.     SkelWindow (wind = GetDemoWind (pyrWindRes),
  290.                 Mouse,            /* mouse clicks */
  291.                 nil,            /* key clicks */
  292.                 Update,            /* updates */
  293.                 Activate,        /* activate/deactivate events */
  294.                 nil,            /* close window */
  295.                 DoWClobber,        /* dispose of window */
  296.                 nil,            /* idle proc */
  297.                 false);            /* irrelevant, since no idle proc */
  298.  
  299.     hMid = wind->portRect.right / 2;
  300.  
  301.  
  302.     donors = MakeCheckersPieces (pieceSize);
  303.     pBlack = GetBlobHandle (donors, 0);
  304.     pWhite = GetBlobHandle (donors, 1);
  305.     MakeCheckerBoard(&boardBlobs, &board, pieceSize);
  306.     misc = NewBlobSet ();
  307.     SetRect (&r, 0, 0, 20, 90);
  308.     OffsetRect (&r, wind->portRect.right - 25,
  309.                     (wind->portRect.bottom - 90 - 25) / 2);
  310.     resetBlob = NewVButtonBlob (misc, &r, "\pReset", true);
  311.     Reset ();
  312.  
  313.     MakeFrontWind (wind);
  314. }
  315.